//
//  StateMachine.m
//  MusicAnalyzer
//
//  Created by jiro on 12/04/04.
//  Copyright 2012 jiro music. All rights reserved.
//

#import "StateMachine.h"

#import "AllStates.h"
#import "StateTransitionInfo.h"

static StateMachine* instance = nil;
static StateMachine* SM = nil;

@implementation StateMachine

@synthesize appController;
@synthesize stateStack;

+ (id) sharedStateMachine
{
	if ( instance == nil )
	{	//	implicit call "+(id)allocWithZone:(NSZone *)zone"
		[ [self alloc ] init ];
	}
	return instance;
}

+ (id)allocWithZone:(NSZone *)zone
{
    @synchronized(self)
	{
        if ( instance == nil)
		{
            instance = [super allocWithZone:zone];
			[ instance setStateStack: [ [ NSMutableArray alloc ] init ] ];
			SM = instance;
            return instance;
        }
    }
    return nil;
}

- (void) transitByCommand: (Command*) command
{
	StateType stateType = [ [ SM currentState ] stateType ];
	CommandType commandType = [ command commandType ];

	switch ( stateType )
	{
	case  StateType_Neutral:
		switch ( commandType )
		{
		case CommandType_ActivateMusicSheetView:
			[ SM popState ];
			[ SM pushState: [ MusicSheetViewActiveState sharedState ] ];
			[ SM pushState: [ MusicSheetChordDeselectedState sharedState ] ];
			break;

		case CommandType_ActivateGraphView:
			[ SM popState ];
			[ SM pushState: [ GraphViewActiveState sharedState ] ];
			[ SM pushState: [ GraphDeselectedState sharedState ] ];
			break;

		case CommandType_ActivateChordTableView:
			[ SM popState ];
			[ SM pushState: [ MusicSheetViewActiveState sharedState ] ];
			[ SM pushState: [ MusicSheetChordDeselectedState sharedState ] ];
			break;
		default:
			@throw ( [ ApplicationErrorException exceptionWithMessage: @"state stack is broken" ] );
		}
		break;

	case StateType_ChordListChordSelectedState:
	case StateType_ChordListChordDeselectedState:
	case StateType_MusicSheetChordSelectedState:
	case StateType_MusicSheetChordDeselectedState:
	case StateType_GraphSelectedState:
	case StateType_GraphDeselectedState:
	case StateType_MusicSheetViewActive:
	case StateType_ChordListActive:
	case StateType_GraphViewActive:
		@throw ( [ NotImplementedException exception ] );
	}
}

- (void) pushState: ( State* ) state
{
	[ stateStack addObject: state ];
}

- (void) popState
{
	if ( 0 == [ stateStack count ] )
	{
		return;
	}
	[ stateStack removeLastObject ];
}

-( State* ) currentState
{
	if ( 0 == [ stateStack count ] )
	{
		return nil;
	}
	return [ stateStack objectAtIndex: [ stateStack count ] - 1 ];
}


- (Command*) inputKeyEvent: (AppKeyEvent*) e
{
	return nil;
}

- (Command*) inputMouseEvent: (AppMouseEvent*) e
{
	State* state = [ self currentState ];
	StateTransitionInfo* info = [ [ StateTransitionInfo alloc ] init ];
	Command* command = [ state commandToMouseEvent: e returnTransitInfo: info ];
	[ self transit: info ];

	return command;
}

- (Command*) inputMidiEvent: (AppMidiEvent*) e
{
	return nil;
}

- (void) transit: (StateTransitionInfo*) info
{
	for ( int i = 0, count = [ info popCount ]; i < count; i++ )
	{
		[ self popState ];
	}
	for ( int i = 0, count = [ [ info pushStates ] count ]; i < count; i++ )
	{
		[ self pushState: [ [ info pushStates ] objectAtIndex: i ] ];
	}
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

- (id)retain
{
    return self;
}
 
- (NSUInteger)retainCount
{
    return UINT_MAX;
}
 
- (void)release
{
}
 
- (id)autorelease
{
    return self;
}

@end
